import patchVnode from './patchVnode'
import createElem from './createElem'

import judge from './judge'


/**
 * 
 * @param {Element} parentElm 
 * @param {Array<Object>} oldCh 
 * @param {Array<Object>} newCh 
 */
export default function updataChildren (parentElm, oldCh, newCh) {
  // 旧children的前后指针
  let oldStartIdx = 0, oldEndIdx = oldCh.length - 1
  // 新children前后指针
  let newStartIdx = 0, newEndIdx = newCh.length - 1
  // 旧的第一个节点、最后一个节点;
  let oldStartVnode = oldCh[oldStartIdx], oldEndVnode = oldCh[oldEndIdx]
  // 新的第一个节点、最后一个节点
  let newStartVnode = newCh[newStartIdx], newEndVnode = newCh[newEndIdx]

  let keymap = null

  while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {
    // 略过加上 undefined 标记
    // if(oldStartVnode == null || oldStartVnode == undefined)
    if (!oldStartVnode) {
      oldStartVnode = oldCh[++oldStartIdx]
    } else if (!oldEndVnode) {
      oldEndVnode = oldCh[--oldEndIdx]
    } if (!newStartVnode) {
      newStartVnode = newCh[++newStartIdx]
    } else if (!newEndVnode) {
      newEndVnode = newCh[--newEndIdx]
    } else if (judge.sameVnode(newStartVnode, oldStartVnode)) {
      // 新前和旧前，对应①情况
      // console.log('1')
      patchVnode(oldStartVnode, newStartVnode)
      oldStartVnode = oldCh[++oldStartIdx]
      newStartVnode = newCh[++newStartIdx]
    } else if (judge.sameVnode(newEndVnode, oldEndVnode)) {
      // 新后与旧后，对应②情况
      // console.log('2')
      patchVnode(oldEndVnode, newEndVnode)
      oldEndVnode = oldCh[--oldEndIdx]
      newEndVnode = newCh[--newEndIdx]
    } else if (judge.sameVnode(newEndVnode, oldStartVnode)) {
      // 新后与旧前，对应③情况
      // console.log('3')
      patchVnode(oldStartVnode, newEndVnode)
      // 此时需要在DOM中，将新前节点插入到旧后节点之后
      parentElm.insertBefore(oldStartVnode.elm, oldEndVnode.elm.nextSibling) 
      oldStartVnode = oldCh[++oldStartIdx]
      newEndVnode = newCh[--newEndIdx]
    } else if (judge.sameVnode(oldEndVnode, newStartVnode)) {
      // 新前与旧后，对应④情况
      // console.log('4')
      patchVnode(oldEndVnode, newStartVnode)
      // 此时需要，将新前节点移动到旧前之前
      parentElm.insertBefore(oldEndVnode.elm, oldStartVnode.elm)
      oldEndVnode = oldCh[--oldEndIdx]
      newStartVnode = newCh[++newStartIdx]
    } else {
      console.log('全部没命中，开始循环查找')
      /**
       * 测试例子：
       * const node0 = h('div', {}, [
          h('p', { key: 'A' }, 'A'),
          h('p', { key: 'B' }, 'B'),
          h('p', { key: 'C' }, 'C'),
          h('p', { key: 'D' }, 'D')
         ])
       */
      // 做 map, createKeyToIdx
      if (!keymap) {
        keymap = {}
        for (let i = oldStartIdx; i < oldEndIdx + 1; ++i) {
          const key = oldCh[i].key
          if (key) {
            keymap[key] = i
          }
        }
      }
      // 接着，寻找 newStartVnode 在 老节点的序号
      const idxInOld = keymap[newStartVnode.key]

      if (!idxInOld) {
        // 此时，说明这个新节点是之前老节点里面没有的（key没有出现过），需要生成dom后加到旧前之前
        parentElm.insertBefore(createElem(newStartVnode), oldStartVnode.elm)
      } else {
        // 这时，说明需要移动。也就是案例的情况三
        const elmToMove = oldCh[idxInOld]
        // 注意，会出现 key相同，但是 选择器不同的情况，但是此时不考虑
        patchVnode(elmToMove, newStartVnode)

        oldCh[idxInOld] = undefined
        parentElm.insertBefore(elmToMove.elm, oldStartVnode.elm)
      }
      // 移动 新节点的的指针，避免死循环
      newStartVnode = newCh[++newStartIdx]
    }
  }

  if (newStartIdx <= newEndIdx) {
    // new 节点列表还有没处理的，插入
    // 这里使用的是newCh的后面位置，让我很不理解。
    // 虽然说，insertBefore对于第二个参数为null会自动插到兄弟节点的最末尾

    // 我的理解是，可能由于 newEndIdx 的上移，会导致它的后面已经 patch 到了dom结构中
    const pivot = newCh[newEndIdx+1] ? newCh[newEndIdx+1].elm : null
    

    
    // 开始插入
    for (let i = newStartIdx; i < newEndIdx + 1; ++i) {
      parentElm.insertBefore(createElem(newCh[i]), pivot)
    }
  } else if (oldStartIdx <= oldEndIdx) {
    for (let i = oldStartIdx; i < oldEndIdx + 1; ++i) {
      if (oldCh[i]) {
        parentElm.removeChild(oldCh[i].elm)
      }
      // 标记已经处理
    }
  }
}
